# -*- coding: utf-8 -*-
import numpy as np
import random

# m denotes the number of examples here, not the number of features
def gradientDescent(x, y, theta, alpha, m, numIterations):
    '''
    梯度下降算法拟合逻辑回归参数值
    numpy乘法运算中"*"是数组元素逐个计算
    dot是按照矩阵乘法的规则来运算
    '''
    xTrans = x.transpose() # 转置矩阵
    for i in range(0, numIterations):
        hypothesis = np.dot(x, theta) # theta 逻辑回归参数
        loss = hypothesis - y # loss 误差
        # avg cost per example (the 2 in 2*m doesn't really matter here.
        # But to be consistent with the gradient, I include it)
        cost = np.sum(loss ** 2) / (2 * m) 
        print("Iteration %d | Cost: %f" % (i, cost))
        # avg gradient per example
        gradient = np.dot(xTrans, loss) / m
        # update
        theta = theta - alpha * gradient # alpha learnig rate 学习率
    return theta


def genData(numPoints, bias, variance):
    '''
    创建数据集
    '''
    x = np.zeros(shape=(numPoints, 2)) # 特征值，numPoints条样本数据，2个特征。numPoints行，2列。
    y = np.zeros(shape=numPoints)      # 标签(label)，numPoints行，1列。
    # basically a straight line
    for i in range(0, numPoints):
        # bias feature
        x[i][0] = 1 # 第一列元素值全位
        x[i][1] = i # 第二列元素值为列数
        # our target variable
        y[i] = (i + bias) + random.uniform(0, 1) * variance # bias偏差值；variance方差。
    return x, y

# gen 100 points with a bias of 25 and 10 variance as a bit of noise
x, y = genData(100, 25, 10)
m, n = np.shape(x)
n_y = np.shape(y)
print "x shape:", str(m), " ", str(n)
print "y length:", str(n_y)

numIterations= 100000 # numIterations 学习次数
alpha = 0.0005        # alpha learning rate 学习率
theta = np.ones(n)    # theta 逻辑回归参数
theta = gradientDescent(x, y, theta, alpha, m, numIterations)
print(theta)